
/**
  ******************************************************************************
  * Copyright 2021 The grapilot Authors. All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  * 
  * http://www.apache.org/licenses/LICENSE-2.0
  * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * 
  * @file       notify.c
  * @author     baiyang
  * @date       2022-1-16
  ******************************************************************************
  */

/*----------------------------------include-----------------------------------*/
#include <string.h>

#include "notify.h"
#include "notify_toshiba_led_i2c.h"

#include <parameter/param.h>
#include <common/time/gp_time.h>
/*-----------------------------------macro------------------------------------*/
#define CONFIG_NOTIFY_DEVICES_MAX 6

#define TOSHIBA_LED_I2C_BUS_INTERNAL    1
#define TOSHIBA_LED_I2C_BUS_EXTERNAL    0

#define ADD_BACKEND(backend) do { add_backend_helper(backend); if (_num_devices >= CONFIG_NOTIFY_DEVICES_MAX) return;} while(0)

/*----------------------------------typedef-----------------------------------*/

/*---------------------------------prototype----------------------------------*/
static void notify_assign_param();
static void add_backend_helper(notify_device_t backend);
static void add_backends(void);
/*----------------------------------variable----------------------------------*/
// The notify flags and values are static to allow direct class access
// without declaring the object.
struct notify_flags_and_values_type notify_flags;
struct notify_events_type notify_events;

static notify_device_t _devices[CONFIG_NOTIFY_DEVICES_MAX];
static uint8_t _num_devices;

static Notify _singleton;
/*-------------------------------------os-------------------------------------*/

/*----------------------------------function----------------------------------*/
/**
  * @brief       
  * @param[in]     
  * @param[out]  
  * @retval      
  * @note        
  */
void notify_ctor()
{
    notify_assign_param();
}

// initialisation
void notify_init(void)
{
    // add all the backends
    add_backends();
}

// main update function, called at 50Hz
void notify_update(void)
{
    for (uint8_t i = 0; i < _num_devices; i++) {
        if (_devices[i] != NULL) {
            notify_device_update(_devices[i]);
        }
    }

    //reset the events
    rt_memset(&notify_events, 0, sizeof(notify_events));
}

// handle a LED_CONTROL message
void notify_handle_led_control(const mavlink_message_t *msg)
{
    for (uint8_t i = 0; i < _num_devices; i++) {
        if (_devices[i] != NULL) {
            notify_device_handle_led_control(_devices[i], msg);
        }
    }
}

// handle RGB from Scripting or AP_Periph
void notify_handle_rgb(uint8_t r, uint8_t g, uint8_t b, uint8_t rate_hz)
{
    for (uint8_t i = 0; i < _num_devices; i++) {
        if (_devices[i] != NULL) {
            notify_device_rgb_control(_devices[i], r, g, b, rate_hz);
        }
    }
}

// handle RGB Per led from Scripting
void notify_handle_rgb_id(uint8_t r, uint8_t g, uint8_t b, uint8_t id)
{
    for (uint8_t i = 0; i < _num_devices; i++) {
        if (_devices[i] != NULL) {
            notify_device_rgb_set_id(_devices[i], r, g, b, id);
        }
    }
}

// handle a PLAY_TUNE message
void notify_handle_play_tune(const mavlink_message_t *msg)
{
    for (uint8_t i = 0; i < _num_devices; i++) {
        if (_devices[i] != NULL) {
            notify_device_handle_play_tune(_devices[i], msg);
        }
    }
}

void notify_play_tune(const char *tune)
{
    for (uint8_t i = 0; i < _num_devices; i++) {
        if (_devices[i] != NULL) {
            notify_device_play_tune(_devices[i], tune);
        }
    }
}

// set flight mode string
void notify_set_flight_mode_str(const char *str)
{
    strncpy(_singleton._flight_mode_str, str, 4);
    _singleton._flight_mode_str[sizeof(_singleton._flight_mode_str)-1] = 0;
}

void notify_send_text(const char *str)
{
    strncpy(_singleton._send_text, str, sizeof(_singleton._send_text));
    _singleton._send_text[sizeof(_singleton._send_text)-1] = 0;
    _singleton._send_text_updated_millis = time_millis();
}

// convert 0-3 to 0-100
int8_t notify_get_rgb_led_brightness_percent()
{
    switch (_singleton._rgb_led_brightness) {
    default:
    case RGB_LED_OFF:
        return 0;
    case RGB_LED_LOW:
        return 33;
    case RGB_LED_MEDIUM:
        return 66;
    case RGB_LED_HIGH:
        return 100;
    }
}

/**
  * @brief       
  * @param[in]     
  * @param[out]  
  * @retval      
  * @note        
  */
static void notify_assign_param()
{
    param_link_variable(PARAM_ID(NTF, NTF_LED_BRIGHT), &_singleton._rgb_led_brightness);
    param_link_variable(PARAM_ID(NTF, NTF_BUZZ_TYPES), &_singleton._buzzer_type);
    param_link_variable(PARAM_ID(NTF, NTF_LED_OVERRIDE), &_singleton._rgb_led_override);
    param_link_variable(PARAM_ID(NTF, NTF_BUZZ_PIN), &_singleton._buzzer_pin);
    param_link_variable(PARAM_ID(NTF, NTF_LED_TYPES), &_singleton._led_type);
    param_link_variable(PARAM_ID(NTF, NTF_BUZZ_ON_LVL), &_singleton._buzzer_level);
    param_link_variable(PARAM_ID(NTF, NTF_BUZZ_VOLUME), &_singleton._buzzer_volume);
    param_link_variable(PARAM_ID(NTF, NTF_LED_LEN), &_singleton._led_len);
}

static void add_backend_helper(notify_device_t backend)
{
    if (backend == NULL) {
        return;
    }

    _devices[_num_devices] = backend;
    _devices[_num_devices]->pNotify = (void *)&_singleton;
    if(!notify_device_init(_devices[_num_devices])) {
        rt_free(_devices[_num_devices]);
        _devices[_num_devices] = NULL;
    } else {
      _num_devices++;
    }
}

// add notify backends to _devices array
static void add_backends(void)
{
    if (_num_devices != 0) {
        return;
    }

#if CONFIG_HAL_BOARD != HAL_BOARD_SITL_WIN
    for (uint32_t i = 1; i < Notify_LED_MAX; i = i << 1) {
        switch(_singleton._led_type & i) {
            case Notify_LED_None:
                break;
            case Notify_LED_Board:
                break;
            case Notify_LED_ToshibaLED_I2C_Internal:
                ADD_BACKEND(toshiba_led_i2c_probe(TOSHIBA_LED_I2C_BUS_INTERNAL));
                break;
            case Notify_LED_ToshibaLED_I2C_External:
                ADD_BACKEND(toshiba_led_i2c_probe(TOSHIBA_LED_I2C_BUS_EXTERNAL));
                break;
            default:
                break;
        }
    }
#endif
}

/*------------------------------------test------------------------------------*/


